﻿using Dapper;
using FastData;
using System;
using System.Data.Entity;
using System.Data.SqlServerCe;
using System.Diagnostics;
using System.Linq;
using System.Web.Configuration;

namespace PerformanceTest
{
    class EntityFrameworkContext : DbContext
    {
        public EntityFrameworkContext()
            : base("SqlCeSample")
        {
            Database.Initialize(true);
        }

        public DbSet<Customer> Customers { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            switch (args[0])
            {
                case "Dapper":
                    Test(() => TestDapper()); 
                    Test(() => TestDapper()); 
                    break;
                case "FastData":
                    Test(() => TestFastData());
                    Test(() => TestFastData());
                    break;
                case "EntityFramework":
                    Test(() => TestEntityFramework());
                    Test(() => TestEntityFramework());
                    break;
                default:
                    Console.Read();
                    break;
            }
        }

        static void TestDapper()
        {
            using (var connection = new SqlCeConnection(WebConfigurationManager.ConnectionStrings["SqlCeSample"].ConnectionString))
            {
                connection.Open();

                Test(id => connection.Query<Customer>("select * from Customer where Id = @Id", new { Id = id }, buffered: false).SingleOrDefault(), "Dapper Query (SingleOrDefault)");
                Test(id => connection.Query<Customer>("select * from Customer", buffered: false).ToList(), "Dapper Query (ToList)");

                //Console.WriteLine();

                //Test(id => connection.Query("select * from Customer where Id = @Id", new { Id = id }, buffered: false).SingleOrDefault(), "Dapper Query (SingleOrDefault-dynamic)");
                //Test(id => connection.Query("select * from Customer", buffered: false).ToList(), "Dapper Query (ToList-dynamic)");
            }
        }

        static void TestFastData()
        {
            using (var data = new DataAccess("SqlCeSample"))
            {
                Test(id => data.Query("select * from Customer where Id = @Id").Param("Id", id).Execute<Customer>().SingleOrDefault(), "FastData Query (SingleOrDefault)");
                Test(id => data.Query("select * from Customer").Execute<Customer>().ToList(), "FastData Query (ToList)");

                //Console.WriteLine();

                //Test(id => data.Select("*").From("Customer").Where("Id", id).Execute<Customer>().SingleOrDefault(), "FastData SelectQuery (SingleOrDefault)");
                //Test(id => data.Select("*").From("Customer").Execute<Customer>().ToList(), "FastData SelectQuery (ToList)");

                //Console.WriteLine();

                Test(id => data.Select<Customer>().Where(c => c.Id == id).SingleOrDefault(), "FastData Select<T> (SingleOrDefault)");
                Test(id => data.Select<Customer>().ToList(), "FastData Select<T>(ToList)");

                //Console.WriteLine();

                //Test(id => data.Query("select * from Customer where Id = @Id").Param("Id", id).Execute<dynamic>().SingleOrDefault(), "FastData Query (SingleOrDefault-dynamic)");
                //Test(id => data.Select("*").From("Customer").Where("Id", id).Execute<dynamic>().SingleOrDefault(), "FastData SelectQuery (SingleOrDefault-dynamic)");
                //Test(id => data.Query("select * from Customer").Execute<dynamic>().ToList(), "FastData Query (ToList-dynamic)");
            }
        }

        static void TestEntityFramework()
        {
            using (var context = new EntityFrameworkContext())
            {
                Test(id => context.Customers.Where(c => c.Id == id).SingleOrDefault(), "EntityFramework 5 (SingleOrDefault)");
                Test(id => context.Customers.ToList(), "EntityFramework 5 (ToList)");

                //Console.WriteLine();

                //Test(id => context.Customers.AsNoTracking().Where(c => c.Id == id).SingleOrDefault(), "EntityFramework 5 (SingleOrDefault-AsNoTracking)");
                //Test(id => context.Customers.AsNoTracking().ToList(), "EntityFramework 5 (ToList-AsNoTracking)");
            }
        }

        static void Test(Action<int> action, string name)
        {
            action(1); //warmup

            var watch = Stopwatch.StartNew();
            for (int i = 1; i <= 100; i++)
            {
                action(i);
            }
            watch.Stop();

            Console.WriteLine(string.Format("{0} => Elapsed time: {1}", name, watch.Elapsed));
        }

        static void Test(Action action)
        {
            GC.Collect();
            long initMemUsage = Process.GetCurrentProcess().WorkingSet64;

            action();

            var memUsage = Process.GetCurrentProcess().WorkingSet64 - initMemUsage;
            if (memUsage < 0)
            {
                memUsage = 0;
            }

            Console.WriteLine(string.Format("[Memory Usage: {0:N2} KB]\n", memUsage / 1024));
        }
    }
}
